#include "samplers.fx"
//________________S T R U C T U R E S_________________________________
struct		Emitter
{
	float4	position	: POSITION;
	float4  direction	: DIRECTION;
	uint	ID			: ID;
	bool    active		: ACTIVE;
	float2  params		: PARAMS; // x: age

	uint	vertexId	: SV_VertexID;
};

struct		VS_OUT
{
	float4	position	: POSITION;
	float4  direction	: DIRECTION;
	uint	ID			: ID;
	bool    active		: ACTIVE;
	float2  params		: PARAMS; // x: age
	uint	vertexId	: VertexID;
};

struct		FireParticle
{
	float4	position	: POSITION;
	float4	direction	: DIRECTION; 
	float4	params		: PARAMETERS;	// x = age, y = alpha
};
//________________V A R I A B L E S___________________________________
static const float pi = 3.14;

Texture2D	tex_heat;
Texture2D	tex_noise;
int			activate_emitter;
int			heatTex_dimension;
float		heat_threshold;
float		time;

//________________H E L P E R  F U N C T I O N S_______________________________________

float3 phongDistribution(float2 uv, float n, float3 axis)
{
	float theta = acos(pow(abs(1-uv.x), 1/(float)(n+1)));
	float phi = 2.0f*pi*uv.y;

	// (theta, phi) -> cartesian
	float3 res = float3(	sin(theta) * cos(phi),
							sin(theta) * sin(phi),
							cos(theta));

	float3 w = axis;
	w = normalize(w);

	float3 t = w;
	float t_min = min(t.x, t.y);
	t_min = min(t_min, t.z);
	if (t_min == t.x) t.x = 1.0f;
	else if (t_min == t.y) t.y = 1.0f;
	else if (t_min == t.z) t.z = 1.0;

	float3 u = cross(t,w);
	u = normalize(u);

	float3 v = cross(w,u);
	v = normalize(v);

	float3x3 xform = { u, v, w };
	res = mul(res, xform);
	return res;
}


//________________S H A D E R S_______________________________________
VS_OUT		VS_EmitParticles(Emitter vin)
{
	VS_OUT vout;
	vout.position = vin.position;
	vout.direction = vin.direction;
	vout.ID = vin.ID;
	vout.active = vin.active;
	vout.vertexId = vin.vertexId;
	return vin;
}

//_________________________________________
[maxvertexcount(10)]
void	GS_EmitParticles(point VS_OUT gin[1], inout PointStream<FireParticle> gstream)
{
	// emit new fire particles
	Emitter emitter = gin[0];

	int x = gin[0].vertexId / heatTex_dimension;
	int y = gin[0].vertexId % heatTex_dimension;

	if (emitter.vertexId == (uint)activate_emitter)
	{
		// emit new particles
		FireParticle particle;
		// initial position equals emitter's position
		particle.position = gin[0].position;
		// direction is the emitter's direction slightly altered 
		float3 rnd = tex_noise.SampleLevel(s_linear, float2(time*2.0f, -time), 0).rgb;
		float3 vec = phongDistribution(rnd.xy, 5, emitter.direction.xyz);
		particle.direction = normalize(float4(vec,0));

		particle.params = float4(/*age*/1.0f, /*alpha*/1.0f , 1, 1);

		gstream.Append(particle);
	}
}

//_________________________________________
GeometryShader gsEmitParticles = ConstructGSWithSO( 
	CompileShader( gs_4_0, GS_EmitParticles() ), 
	"POSITION.xyzw; DIRECTION.xyzw; PARAMETERS.xyzw" );




DepthStencilState disabled
{
	DepthEnable = false;
	DepthWriteMask = false;
};



technique10 EmitParticles
{
	pass P0
	{
		SetVertexShader( CompileShader ( vs_4_0, VS_EmitParticles() ) );
		SetGeometryShader( gsEmitParticles );
		SetPixelShader( NULL );
		

		SetBlendState(0, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff);
		SetRasterizerState(0);
		SetDepthStencilState(disabled, 0);
	}
}

